
`include "common_header.verilog"

//  *************************************************************************
//  File : stats_collect_txsym_xl
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized Reproduction or Use is Expressly Prohibited.
//  Copyright (c) 2014 MoreThanIP.com, Germany
//  Designed by : Daniel Koehler
//  support@morethanip.com
//  *************************************************************************
//  Description: Implement read/modify/write counters.
//               Resorts and controls the reading of the counters according
//               to the MAC register map.
//               Symmetric TX, reusing all the RX counters by emulating 
//               an identical stats vector.
//  Version    : $Id: stats_collect_txsym_xl.v,v 1.6 2017/07/06 15:13:26 gc Exp $
//  *************************************************************************

module stats_collect_txsym_xl (

`ifdef MTIP_SDPM_GEN_GLOBAL_RST
   sdpm_core_reset,
   sdpm_bist_i,
   sdpm_bist_o,
`endif
   reset,
   clk,
   stc_clearread,
   stc_saturate,
   tx_mtu,
   stats_rd,
   mreg_sel,
   stats_clear,
   stats_clearvalue,
   stats_busy,
   stats_rdata,
`ifdef STAT_PFCCNT_ENA
   tsv_stat_pfc,
`endif          
   tsv_stat_val,
   tsv_stat
`ifdef MTIPSTAT_MEM_EXTERNAL
   ,
   tstm_raddr,
   tstm_rden,
   tstm_rdata,
   tstm_wren,
   tstm_waddr,
   tstm_wdata
`endif
   );

parameter CNTWIDTH       = 64;
parameter CNTSATURATEOPT = 0;
`ifdef STAT_PFCCNT_ENA
parameter PFC_PRIORITIES = 8; // Set to 8 or 16
`endif

`ifdef MTIP_SDPM_GEN_GLOBAL_RST
input   sdpm_core_reset;        // global memory reset for special memories
input   [`MTIP_SDPM_GEN_BIST_I:0] sdpm_bist_i;  // inputs to ALL memories but not necessarily all used in this instance.
output  [`MTIP_SDPM_GEN_BIST_O:0] sdpm_bist_o;  // outputs OR'ed from ALL memories when travelling up the hierarchies
`endif
input   reset;                          //  async active high
input   clk;                            //  line clock
input   stc_clearread;                  //  configuration: clear counter on read
input   stc_saturate;                   //  configuration: counters saturate (1) / wrap around (0)
input   [15:0] tx_mtu;                  //  TX max valid length
input   stats_rd;                       //  read request
input   [7:0] mreg_sel;                 //  address in MAC address space
input   stats_clear;                    //  clear all counters
input   [CNTWIDTH-1:0] stats_clearvalue;//  value to write into memory during clear 
output  stats_busy;                     //  statistics read busy
output  [CNTWIDTH - 1:0] stats_rdata;   //  statistics read data return
`ifdef STAT_PFCCNT_ENA
input   [PFC_PRIORITIES-1:0] tsv_stat_pfc;             //  the class enable of latest generated PFC frame
`endif
input   tsv_stat_val;                   //  statistic Vector Valid (pulse)
input   [24:0] tsv_stat;                //  receive Statistic Vector

`ifdef MTIPSTAT_MEM_EXTERNAL

        `ifdef STAT_PFCCNT_ENA
        localparam CNTADDR       = 6;            //  address bits
        `else
        localparam CNTADDR       = 5;            //  address bits
        `endif

output  [CNTADDR-1:0]   tstm_raddr;                     // Stats TX mem Read address (txclk)
output                  tstm_rden;                      // Stats TX mem read enable (txclk)
input   [CNTWIDTH+CNTSATURATEOPT-1:0] tstm_rdata;       // Stats TX mem Read data (txclk)
output                  tstm_wren;                      // Stats TX mem write (txclk)
output  [CNTADDR-1:0]   tstm_waddr;                     // Stats TX mem write addres (txclk)
output  [CNTWIDTH+CNTSATURATEOPT-1:0] tstm_wdata;       // Stats TX mem write data (txclk)

wire    [CNTADDR-1:0]   tstm_raddr;
wire                    tstm_rden; 
wire                    tstm_wren; 
wire    [CNTADDR-1:0]   tstm_waddr;
wire    [CNTWIDTH+CNTSATURATEOPT-1:0] tstm_wdata;
`endif


wire    stats_busy; 
wire    [CNTWIDTH - 1:0] stats_rdata; 

wire    frm_align_err;                  //  Received Frame Aligment Error Indication
wire    rsv_stat_val;                   //  statistic Vector Valid (pulse)
wire    [31:0] rsv_stat;                //  receive Statistic Vector
wire    [7:0] mreg_sel_int;             //  address in MAC address space
wire    len_gt_max;                     //  octets greater than MTU

//  convert the tx stats vector into a compatible rsv_stat vector
//  -------------------------------------------------------------

assign len_gt_max       = tsv_stat[15:0] > tx_mtu ? 1'b 1 : 1'b 0;

assign frm_align_err    = 1'b 0; 
assign rsv_stat_val     = tsv_stat_val; 
assign rsv_stat[15:0]   = tsv_stat[15:0]; 
assign rsv_stat[16]     = 1'b 0;        //  phy err
assign rsv_stat[17]     = tsv_stat[16] == 1'b 0 ? 1'b 1 : 1'b 0; //  only if application driven error => RX17:crc err
assign rsv_stat[18]     = 1'b 0;        //  length out of range
assign rsv_stat[19]     = len_gt_max;   //  toolong
assign rsv_stat[20]     = tsv_stat[16] & len_gt_max==1'b 0; //  frame ok
assign rsv_stat[21]     = tsv_stat[17]; //  unicast
assign rsv_stat[22]     = tsv_stat[18]; //  mcast
assign rsv_stat[23]     = tsv_stat[19]; //  bcast
assign rsv_stat[24]     = tsv_stat[21]; //  control frame
assign rsv_stat[25]     = tsv_stat[22]; //  good pause
assign rsv_stat[26]     = tsv_stat[23]; //  vlan 
assign rsv_stat[27]     = tsv_stat[24]; //  stacked vlan
assign rsv_stat[28]     = tsv_stat[20]; //  TX20: FIFO underrun => RX28:frame truncated (FIFO overflow)
assign rsv_stat[29]     = ((tsv_stat[20] == 1'b 0) & (tsv_stat[15:0] < 16'h 0040)) ? 1'b 1 : 1'b 0; //  RUNT (too short, good+bad) but not when FIFO underrun
assign rsv_stat[30]     = 1'b 0;        //  rs fault
assign rsv_stat[31]     = 1'b 0;        //  frame err (code error from phy, invalid XGMII code)

//  map accesses of 0x200..x2ff (0x80..0xBF) into 0x0100..0x1ff where the RX stat logic responds to.
//  PFC counters: 0x3c0 .. 0x3ff not remapped, as rxs will assume all above 0x380 to be PFC counters and only 8 of them
//  (see stats_maprxcnt)
assign mreg_sel_int = {mreg_sel[6], mreg_sel[7], //  0x80 -> 0x40, 0xc0 -> 0xc0
                       mreg_sel[5:0]}; 

//  --------------------------------
//  use the RX statistics module
//  --------------------------------
stats_collect_rx_xl 
        #(
        .CNTWIDTH(CNTWIDTH),
        .CNTSATURATEOPT(CNTSATURATEOPT)
`ifdef STAT_PFCCNT_ENA
        , .PFC_PRIORITIES(PFC_PRIORITIES)
`endif
        ) 
U_TXSTATSYM (

        `ifdef MTIP_SDPM_GEN_GLOBAL_RST
          .sdpm_core_reset(sdpm_core_reset),
          .sdpm_bist_i(sdpm_bist_i),
          .sdpm_bist_o(sdpm_bist_o),
        `endif
          .reset(reset),
          .clk(clk),
          .stc_clearread(stc_clearread),
          .stc_saturate(stc_saturate),
          .stats_rd(stats_rd),
          .mreg_sel(mreg_sel_int),
          .stats_clear(stats_clear),
          .stats_clearvalue(stats_clearvalue),
          .stats_busy(stats_busy),
          .stats_rdata(stats_rdata),
          .frm_align_err(frm_align_err),
        `ifdef STAT_PFCCNT_ENA
          .rsv_stat_pfc(tsv_stat_pfc),
        `endif
          .rsv_stat_val(rsv_stat_val),
          .rsv_stat(rsv_stat)
        `ifdef MTIPSTAT_MEM_EXTERNAL
           ,
           .rstm_raddr(tstm_raddr),
           .rstm_rden (tstm_rden ),
           .rstm_rdata(tstm_rdata),
           .rstm_wren (tstm_wren ),
           .rstm_waddr(tstm_waddr),
           .rstm_wdata(tstm_wdata)
        `endif
          
          );

endmodule // module stats_collect_txsym_xl

